package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	retalog "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"math"
	"os"
	"roomAdmin/utils"
	"time"
)

// 日志
func Logger() gin.HandlerFunc {

	src, err := os.OpenFile(utils.LogSetting.FilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println("err:",err)
	}

	// 实例化出来一个logger对象
	logger := logrus.New()

	// 将log日志写入log文件中
	logger.Out = src

	// 设置日志级别
	logger.SetLevel(logrus.DebugLevel)

	// 日志分隔
	logWrite, _ := retalog.New(
		utils.LogSetting.FilePath +"log%Y%m%d.log",
		// 最大保存时间
		retalog.WithMaxAge(7*24*time.Hour),
		// 什么时候分隔
		retalog.WithRotationTime(24*time.Hour),
		// 设置软连接
		retalog.WithLinkName(utils.LogSetting.LinkName),
	)

	// 需要写入的内容
	writerMap := lfshook.WriterMap{
		logrus.InfoLevel:  logWrite,
		logrus.FatalLevel: logWrite,
		logrus.DebugLevel: logWrite,
		logrus.WarnLevel:  logWrite,
		logrus.ErrorLevel: logWrite,
		logrus.PanicLevel: logWrite,
		logrus.TraceLevel: logWrite,
	}

	// 实例化hook
	Hook := lfshook.NewHook(writerMap,&logrus.TextFormatter{
		// 内容格式化
		// 时间格式化
		TimestampFormat: "2006-01-02 15:04:05",
	})

	logger.AddHook(Hook)

	return func(c *gin.Context) {
		// 记录请求每个接口所需的时间
		startTime := time.Now()

		c.Next()

		stopTime := time.Since(startTime)
		// 花销时间，毫秒为单位
		//spendTime := int(math.Ceil(float64(stopTime.Nanoseconds())/1000000.0))
		spendTime := fmt.Sprintf("%d ms", int(math.Ceil(float64(stopTime.Nanoseconds())/1000000.0)))

		// 请求的主机名字
		hostName, err := os.Hostname()
		if err != nil {
			hostName = "unknown"
		}

		// 请求状态码
		statusCode := c.Writer.Status()

		// 客户端ip
		clientIp := c.ClientIP()

		// 请求方式
		userAgent := c.Request.UserAgent()

		// 请求长度
		dataSize := c.Writer.Size()
		// 由于dataSize不可能为0，格式化一下数据
		if dataSize < 0{
			dataSize = 0
		}

		// 请求类型
		method := c.Request.Method

		// 请求的路径
		path := c.Request.RequestURI

		entry := logger.WithFields(logrus.Fields{
			"HostName" : hostName,
			"Status" : statusCode,
			"SpendTime" : spendTime,
			"Ip" : clientIp,
			"Method" : method,
			"Path" : path,
			"DataSize" : dataSize,
			"Agent" : userAgent,
		})

		// 正常的ERR错误
		if len(c.Errors) > 0 {
			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
		}

		// 服务器错误
		if statusCode >= 500 {
			entry.Error()
		}else if statusCode >= 400 {
			entry.Warn()
		}else {
			// 成功请求
			entry.Info()
		}

	}
}